export const metadata = {
  title: "Next.js",
  description: "Next.js integration for T3 Env",
};

# Next.js

The Next.js package comes preconfigured for Next.js and also enforces some extra rules by default to make sure you have out-of-the-box compatibility in all different Next.js runtimes.

<Steps>

### Install dependencies

Install the required dependencies:

```bash
pnpm add @t3-oss/env-nextjs zod

# or using JSR
deno add jsr:@t3-oss/env-nextjs
```

<Callout>

Although we'll use Zod as examples throughout these docs, you can use any validator that supports [Standard Schema](https://github.com/standard-schema/standard-schema).

</Callout>

<Callout>

`@t3-oss/env-nextjs` requires a minimum of `typescript@5.0.0`.

</Callout>

<Callout>

`@t3-oss/env-nextjs` is an ESM only package. Make sure that your tsconfig uses a module resolution that can read `package.json#exports` (`Bundler` is recommended).

</Callout>

### Create your schema

```ts title="src/env.ts"
import { createEnv } from "@t3-oss/env-nextjs";
import { z } from "zod";

export const env = createEnv({
  server: {
    DATABASE_URL: z.url(),
    OPEN_AI_API_KEY: z.string().min(1),
  },
  client: {
    NEXT_PUBLIC_PUBLISHABLE_KEY: z.string().min(1),
  },
  // If you're using Next.js < 13.4.4, you'll need to specify the runtimeEnv manually
  runtimeEnv: {
    DATABASE_URL: process.env.DATABASE_URL,
    OPEN_AI_API_KEY: process.env.OPEN_AI_API_KEY,
    NEXT_PUBLIC_PUBLISHABLE_KEY: process.env.NEXT_PUBLIC_PUBLISHABLE_KEY,
  },
  // For Next.js >= 13.4.4, you only need to destructure client variables:
  // experimental__runtimeEnv: {
  //   NEXT_PUBLIC_PUBLISHABLE_KEY: process.env.NEXT_PUBLIC_PUBLISHABLE_KEY,
  // }
});
```

<Callout type="info">

Unlike in the core package, `runtimeEnv` is strict by default, meaning you'll have to destructure all the keys manually. This is due to how Next.js bundles environment variables and only explicitly accessed variables are included in the bundle. Missing keys will result in a type-error:

![missing runtimeEnv](https://user-images.githubusercontent.com/51714798/234409775-fee3edbd-a73b-415a-829f-28f6f6092707.png)

</Callout>

<Callout type="warning">

While defining both the client and server schemas in a single file provides the best developer experience,
it also means that your validation schemas for the server variables will be shipped to the client.
If you consider the **names** of your variables sensitive, you should split your schemas into two files.

```ts title="src/env/server.ts"
import { createEnv } from "@t3-oss/env-nextjs";
import { z } from "zod";

export const env = createEnv({
  server: {
    DATABASE_URL: z.url(),
    OPEN_AI_API_KEY: z.string().min(1),
  },
  // If you're using Next.js < 13.4.4, you'll need to specify the runtimeEnv manually
  // runtimeEnv: {
  //   DATABASE_URL: process.env.DATABASE_URL,
  //   OPEN_AI_API_KEY: process.env.OPEN_AI_API_KEY,
  // },
  // For Next.js >= 13.4.4, you can just reference process.env:
  experimental__runtimeEnv: process.env
});
```

```ts title="src/env/client.ts"
import { createEnv } from "@t3-oss/env-nextjs";
import { z } from "zod";

export const env = createEnv({
  client: {
    NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1),
  },
  runtimeEnv: {
    NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY,
  },
});
```

</Callout>

<Callout type="info">

If you're using the `standalone` output in your `next.config.ts`, make sure to include the following:  

```ts title="next.config.ts"
import type { NextConfig } from "next"

const nextConfig: NextConfig = {
  output: "standalone",
  // Add the packages in transpilePackages
  transpilePackages: ["@t3-oss/env-nextjs", "@t3-oss/env-core"],
}

export default nextConfig
```

</Callout>

### Validate schema on build (recommended)

We recommend you importing your newly created file in your `next.config.js`. This will make sure your environment variables are validated at build time which will save you a lot of time and headaches down the road. You can use [unjs/jiti](https://github.com/unjs/jiti) to import TypeScript files in your `next.config.js`:

```js title="next.config.js" {6}
import { fileURLToPath } from "node:url";
import createJiti from "jiti";
const jiti = createJiti(fileURLToPath(import.meta.url));

// Import env here to validate during build. Using jiti@^1 we can import .ts files :)
jiti("./app/env");

/** @type {import('next').NextConfig} */
export default {
  /** ... */
};
```

We do not recommend using `next.config.ts` as it does not support loading ESM. 

### Use your schema

Then, import the `env` object in your application and use it, taking advantage of type-safety and auto-completion:

```ts title="some-api-endpoint.ts"
import { env } from "~/env"; // On server

export const GET = async () => {
  // do fancy ai stuff
  const magic = await fetch("...", {
    headers: { Authorization: env.OPEN_AI_API_KEY },
  });
  // ...
};
```

```ts title="some-component.tsx"
import { env } from "~/env"; // On client - same import!

export const SomeComponent = () => {
  return (
    <SomeProvider publishableKey={env.PUBLIC_PUBLISHABLE_KEY}>
      {/* ... */}
    </SomeProvider>
  );
};
```

</Steps>
